﻿using System;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;

public class EliminationSystem : SystemBase {

    public EventHandler<int> OnEliminated;

    public Entity gameEntity;

    private EntityCommandBufferSystem commandBufferSystem;
    private NativeArray<byte> markArray;
    // private NativeArray<Entity> gameEntities;
    private DynamicBuffer<MinoGridState> minoGrids;
    private MinoGridEvent mgEvent;

    protected override void OnCreate() {
        base.OnCreate();
    }

    protected override void OnStartRunning() {
        base.OnStartRunning();
        commandBufferSystem = World.GetOrCreateSystem<EntityCommandBufferSystem>();

        mgEvent = EntityManager.GetComponentData<MinoGridEvent>(gameEntity);
    }

    protected override void OnUpdate() {
        DestoryNativeArray();

        mgEvent = GetComponent<MinoGridEvent>(gameEntity);
        if (MinoGridEventType.FinishMoving == mgEvent.Value) {
            minoGrids = EntityManager.GetBuffer<MinoGridState>(gameEntity);
            NativeArray<byte> tmpMarkArray = new NativeArray<byte>(20, Allocator.TempJob);
            markArray = tmpMarkArray;
            EntityManager.SetComponentData(gameEntity, new MinoGridEvent { Value = MinoGridEventType.CreateTetromino });

            // 检测一下是否需要消行
            // - 统计满行的 y 值：从 y 的下标 1 开始，排除 x = 0 & maxX
            // - 由上至下复写
            int markCount = 0;
            for (int y = 1, yCount = GlobalValue.GridRowCount; y < yCount; y++) {
                bool full = true;
                for (int x = 1, xCount = GlobalValue.GridColumnCount - 1; x < xCount; x++) {
                    int idx = y * GlobalValue.GridColumnCount + x;
                    if (0 == minoGrids[idx].Value) {
                        full = false;
                        break;
                    }
                }
                if (full) {
                // 统计行编号
                    tmpMarkArray[markCount] = (byte)y;
                    markCount++;
                }
            }
            if (markCount > 0) {
                // 更新积分
                OnEliminated?.Invoke(this, markCount);

                // 更新 Grids
                int skipCount = 0;
                for (int y = 1, yCount = GlobalValue.GridRowCount; y < yCount; y++) {
                    bool notEliminationRow = y != tmpMarkArray[skipCount];
                    if (y > tmpMarkArray[skipCount]) {
                        skipCount = math.min(markCount, skipCount + 1);
                    }
                    if (skipCount > 0 && notEliminationRow) { 
                        for (int x = 1, xCount = GlobalValue.GridColumnCount - 1; x < xCount; x++) {
                            int srcIdx = y * GlobalValue.GridColumnCount + x;
                            int targetIdx = (y - skipCount) * GlobalValue.GridColumnCount + x;
                            minoGrids[targetIdx] = minoGrids[srcIdx];
                            var curGrid = minoGrids[srcIdx];
                            curGrid.Value = 0;
                            minoGrids[srcIdx] = curGrid;
                        }
                    }
                }
                // 消除无效的 Entities
                var cmdBuffer = commandBufferSystem.CreateCommandBuffer().ToConcurrent();
                Entities.WithoutBurst().ForEach((Entity entity, int entityInQueryIndex, ref Translation pos, in StaticMinoTag staticTag) => {
                    int moveStep = 0;
                    for (int i = 0, iCount = markCount; i < iCount; i++) {
                        if (pos.Value.y == tmpMarkArray[i]) {
                            // 位移为即刻执行，而删除操作则是要延迟到 SyncPoint 才会执行
                            // 所以此处把 Mino 移除到屏幕外
                            // 用于避免这种可见的延迟效果
                            pos.Value.y -= 10000;
                            // 若改行索引被标记为“删除”，则删除 Entity 
                            cmdBuffer.DestroyEntity(entityInQueryIndex, entity);
                            break;
                        } else if (tmpMarkArray[i] < pos.Value.y) {
                            // 否则，记录下移行数
                            moveStep++;
                        }
                    }
                    if (moveStep > 0) { 
                        pos.Value.y -= moveStep;
                    }
                }).ScheduleParallel();
                commandBufferSystem.AddJobHandleForProducer(Dependency);
            }
        }
    }
    protected override void OnStopRunning() {
        DestoryNativeArray();
        base.OnStopRunning();
    }

    private void DestoryNativeArray() { 
        if (markArray.IsCreated) {
            markArray.Dispose();
        }
        //if (gameEntities.IsCreated) {
        //    gameEntities.Dispose();
        //}
    }
}
